package com.smasher.anim;

import android.animation.Animator;
import android.view.View;
import android.view.animation.Interpolator;

import androidx.annotation.NonNull;

import java.util.ArrayList;
import java.util.List;


/**
 *
 *
 * <p>Android动画控制类，提供链式调用配置动画参数</p>
 *
 * <h3>使用示例：</h3>
 * <pre>{@code
 * // 基础使用
 * Pixar.with(AnimType.Shake)
 *     .duration(1000)
 *     .playOn(view);
 *
 * // 完整配置示例
 * Pixar.with(AnimType.BounceIn)
 *     .duration(1200)
 *     .delay(300)
 *     .repeat(2) // -1表示无限循环
 *     .pivot(view.getWidth()/2f, view.getHeight())
 *     .interpolate(new BounceInterpolator())
 *     .onEnd(anim -> {
 *         // 动画结束回调
 *     })
 *     .playOn(imageView);
 * }</pre>
 *
 * <h3>关键配置项：</h3>
 * <ul>
 *   <li>{@code duration(long)} - 动画时长（默认1000ms）</li>
 *   <li>{@code delay(long)} - 开始延迟（默认0ms）</li>
 *   <li>{@code repeat(int)} - 重复次数（0不重复，-1无限循环）</li>
 *   <li>{@code pivot(float,float)} - 设置变换锚点坐标</li>
 *   <li>{@code interpolate(Interpolator)} - 设置动画插值器</li>
 *   <li>{@code onStart/End/Repeat/Cancel} - 动画生命周期回调</li>
 * </ul>
 *
 * <h3>动画控制：</h3>
 * <pre>{@code
 * Pixar.PixarAnimator animator = Pixar.with(AnimType.FlipInX).playOn(view);
 * if (animator.isRunning()) {
 *     animator.stop();    // 停止并重置视图
 *     animator.stop(false); // 停止但保持当前状态
 * }
 * }</pre>
 */
public class Pixar {
    private static final long DURATION = BaseViewAnimator.DURATION;
    private static final long NO_DELAY = 0;
    public static final int INFINITE = -1;
    public static final float CENTER_PIVOT = Float.MAX_VALUE;

    private final BaseViewAnimator animator;
    private boolean repeat;
    private final long duration;
    private final long delay;
    private long repeatTimes;
    private final Interpolator interpolator;
    private final float pivotX;
    private final float pivotY;
    private final List<Animator.AnimatorListener> callbacks;
    private final View target;

    private Pixar(AnimationComposer animationComposer) {
        animator = animationComposer.animator;
        duration = animationComposer.duration;
        delay = animationComposer.delay;
        repeat = animationComposer.repeat;
        repeatTimes = animationComposer.repeatTimes;
        interpolator = animationComposer.interpolator;
        pivotX = animationComposer.pivotX;
        pivotY = animationComposer.pivotY;
        callbacks = animationComposer.callbacks;
        target = animationComposer.target;
    }

    public static AnimationComposer with(AnimType animType) {
        return new AnimationComposer(animType);
    }

    public static AnimationComposer with(BaseViewAnimator animator) {
        return new AnimationComposer(animator);
    }

    private static class EmptyAnimatorListener implements Animator.AnimatorListener {
        @Override
        public void onAnimationStart(@NonNull Animator animation) {
        }

        @Override
        public void onAnimationEnd(@NonNull Animator animation) {
        }

        @Override
        public void onAnimationCancel(@NonNull Animator animation) {
        }

        @Override
        public void onAnimationRepeat(@NonNull Animator animation) {
        }
    }

    public static final class AnimationComposer {
        private final List<Animator.AnimatorListener> callbacks = new ArrayList<>();
        private final BaseViewAnimator animator;
        private long duration = DURATION;
        private long delay = NO_DELAY;
        private boolean repeat = false;
        private long repeatTimes = 0;
        private float pivotX = Pixar.CENTER_PIVOT, pivotY = Pixar.CENTER_PIVOT;
        private Interpolator interpolator;
        private View target;

        private AnimationComposer(AnimType animType) {
            this.animator = animType.getAnimator();
        }

        private AnimationComposer(BaseViewAnimator animator) {
            this.animator = animator;
        }

        public AnimationComposer duration(long duration) {
            this.duration = duration;
            return this;
        }

        public AnimationComposer delay(long delay) {
            this.delay = delay;
            return this;
        }

        public AnimationComposer interpolate(Interpolator interpolator) {
            this.interpolator = interpolator;
            return this;
        }

        public AnimationComposer pivot(float pivotX, float pivotY) {
            this.pivotX = pivotX;
            this.pivotY = pivotY;
            return this;
        }

        public AnimationComposer pivotX(float pivotX) {
            this.pivotX = pivotX;
            return this;
        }

        public AnimationComposer pivotY(float pivotY) {
            this.pivotY = pivotY;
            return this;
        }

        public AnimationComposer repeat(int times) {
            if (times < INFINITE) {
                throw new RuntimeException("Can not be less than -1, -1 is infinite loop");
            }
            repeat = times != 0;
            repeatTimes = times;
            return this;
        }

        public AnimationComposer withListener(Animator.AnimatorListener listener) {
            callbacks.add(listener);
            return this;
        }

        public AnimationComposer onStart(final AnimatorCallback callback) {
            callbacks.add(new EmptyAnimatorListener() {

                @Override
                public void onAnimationStart(@NonNull Animator animation) {
                    callback.call(animation);
                }
            });
            return this;
        }

        public AnimationComposer onEnd(final AnimatorCallback callback) {
            callbacks.add(new EmptyAnimatorListener() {

                @Override
                public void onAnimationEnd(@NonNull Animator animation) {
                    callback.call(animation);
                }
            });
            return this;
        }

        public AnimationComposer onCancel(final AnimatorCallback callback) {
            callbacks.add(new EmptyAnimatorListener() {

                @Override
                public void onAnimationCancel(@NonNull Animator animation) {
                    callback.call(animation);
                }
            });
            return this;
        }

        public AnimationComposer onRepeat(final AnimatorCallback callback) {
            callbacks.add(new EmptyAnimatorListener() {

                @Override
                public void onAnimationRepeat(@NonNull Animator animation) {
                    callback.call(animation);
                }
            });
            return this;
        }

        public PixarAnimator playOn(View target) {
            this.target = target;
            return new PixarAnimator(new Pixar(this).play(), this.target);
        }
    }

    /**
     * YoYo string, you can use this string to control your YoYo.
     */
    public static final class PixarAnimator {
        private final BaseViewAnimator animator;
        private final View target;

        private PixarAnimator(BaseViewAnimator animator, View target) {
            this.target = target;
            this.animator = animator;
        }

        public boolean isStarted() {
            return animator.isStarted();
        }

        public boolean isRunning() {
            return animator.isRunning();
        }

        public void stop() {
            stop(true);
        }

        public void stop(boolean reset) {
            animator.cancel();
            if (reset)
                animator.reset(target);
        }
    }

    private BaseViewAnimator play() {
        animator.setTarget(target);

        if (pivotX == Pixar.CENTER_PIVOT) {
            target.setPivotX(target.getMeasuredWidth() / 2.0f);
        } else {
            target.setPivotX(pivotX);
        }
        if (pivotY == Pixar.CENTER_PIVOT) {
            target.setPivotX(target.getMeasuredHeight() / 2.0f);
        } else {
            target.setPivotY(pivotY);
        }

        animator.setDuration(duration)
                .setInterpolator(interpolator)
                .setStartDelay(delay);

        if (!callbacks.isEmpty()) {
            for (Animator.AnimatorListener callback : callbacks) {
                animator.addAnimatorListener(callback);
            }
        }

        if (repeat) {
            animator.addAnimatorListener(new Animator.AnimatorListener() {
                private long currentTimes = 0;

                @Override
                public void onAnimationStart(@NonNull Animator animation) {
                    currentTimes++;
                }

                @Override
                public void onAnimationEnd(@NonNull Animator animation) {
                    if (!repeat) {
                        return;
                    }
                    if (repeatTimes == INFINITE || currentTimes < repeatTimes) {
                        animator.restart();
                    }
                }

                @Override
                public void onAnimationCancel(@NonNull Animator animation) {
                    repeatTimes = 0;
                    repeat = false;
                }

                @Override
                public void onAnimationRepeat(@NonNull Animator animation) {
                }
            });
        }

        animator.animate();
        return animator;
    }

}
